package com.rich.datapump.biz.template

import com.alibaba.excel.EasyExcel
import com.alibaba.excel.write.metadata.WriteSheet
import com.rich.datapump.biz.metadata.Column
import com.rich.datapump.biz.metadata.MetadataBean
import org.beetl.core.Configuration
import org.beetl.core.GroupTemplate
import org.beetl.core.Template
import org.beetl.core.exception.BeetlException
import org.beetl.core.exception.ErrorInfo
import org.noear.solon.annotation.Controller
import org.noear.solon.annotation.Mapping
import java.io.File
import java.io.FileWriter
import java.io.IOException
import java.util.*


@Controller
@Mapping("templateResult")
class TRController {

    private fun openDir(path:String){
        Runtime.getRuntime().exec("explorer.exe /select,$path")
    }

    /** Excel部分 **/

    @Mapping("metadata2Excel")
    fun metadata2Excel(
        data:TRDataBean
    ){
        val f = File(data.destPath, System.currentTimeMillis().toString() + ".xlsx")
        if (!f.exists()) {
            f.getParentFile().mkdirs()
            f.createNewFile()
        }
        data.metadatas?.let {
            EasyExcel.write(f, Column::class.java).build().use { excelWriter ->
                for (i in it.indices) {
                    val mdb: MetadataBean = it[i]
                    val writeSheet: WriteSheet = EasyExcel.writerSheet(i, mdb.tableName)
                        .head(headGenerate(mdb, Column::class.java)).build()
                    excelWriter.write(mdb.columns, writeSheet)
                }
            }
        }
        // 打开目录
        data.destPath?.let { openDir(it) }
    }

    private fun headGenerate(md: MetadataBean, columnClass: Class<Column>): List<List<String?>> =
        // 分析columnClass 获取字段名 然后填充标题
        ArrayList<List<String?>>().apply {
            for (f in columnClass.declaredFields) {
                val head0: MutableList<String?> = ArrayList()
                head0.add(md.tableName)
                head0.add(md.tableComment)
                head0.add(f.name)
                this.add(head0)
            }
        }

    /** 模版部分 **/
    @Mapping("templateByBeetl")
    fun templateByBeetl(
        data:TRDataBean
    ){
        //初始化代码
        val tmpRoot: String? = data.templateRootPath
        tmpRoot?.let { tr ->


            val resourceLoader = org.beetl.core.resource.FileResourceLoader(tr, "utf-8")
            val cfg: Configuration = Configuration.defaultConfiguration()
            val gt = GroupTemplate(resourceLoader, cfg)

            // 获取模版目录下所有模版文件 以.tmp结尾的文件
            val rootDir = File(tr)
            if (!rootDir.exists() || !rootDir.isDirectory) throw RuntimeException("目录不存在或指定路径不是目录")

            val metadatas = data.metadatas

            val outRoot = data.destPath
            rootDir.listFiles { _, name -> name.endsWith("tmp") }?.forEach { tFile: File ->
                //获取模板
                val tFileName = tFile.name
                metadatas?.forEach { m ->
                    val t: Template = gt.getTemplate(tFileName)
                    // 模版校验
                    checkTemplate(t)

                    // 绑定模版数据
                    t.binding("md", m)
                    t.binding("columns", m.columns)

                    // 创建输出目录
                    val destFile = File(
                        outRoot + m.nameHump,
                        m.namePascal + tFileName.substring(0, tFileName.lastIndexOf(".tmp"))
                    )
                    if (!destFile.parentFile.exists()) {
                        destFile.parentFile.mkdirs()
                    }
                    // 输出结果
                    try {
                        FileWriter(destFile).use { fw ->
                            if (!destFile.exists()) destFile.createNewFile()
                            t.renderTo(fw)
                        }
                    } catch (e: IOException) {
                        throw RuntimeException(e)
                    }
                }
            }

            // 打开目录
            data.destPath?.let { openDir(it) }
        }
    }


    private fun checkTemplate(t: Template) {
        val ex: BeetlException = t.validate() ?: return
        val error = ErrorInfo(ex)
        val line: Int = error.getErrorTokenLine()
        val errorToken: String = error.getErrorTokenText()
        val type: String = error.getType()
        throw java.lang.RuntimeException("line:$line errorToken:$errorToken type:$type")
    }

}